#include <GLUT/glut.h>

#include "core.h"
#include "keyboard.h"


namespace keyboard {
    bool last_key_down[KEY_LIMIT];
    bool this_key_down[KEY_LIMIT];
    bool key_down[KEY_LIMIT];

    void _set_key(unsigned char c, bool down);
    void _set_special(int key, bool down);
    void _keyboard_func(unsigned char c, int x, int y);
    void _keyboard_up_func(unsigned char c, int x, int y);
    void _special_func(int key, int x, int y);
    void _special_up_func(int key, int x, int y);
    
    struct { char c; int k; } _mapping[] = {
        {27, KEY_ESCAPE},
        {' ', KEY_SPACE},
        {'a', KEY_A},
        {'m', KEY_M},
        {'o', KEY_O},
        {'p', KEY_P},
        {'q', KEY_Q},
    };
    
    void _set_key(unsigned char c, bool down) {
        for (int i = 0; i < N_ELEMS(_mapping); ++i) {
            if (_mapping[i].c == c) {
                key_down[_mapping[i].k] = down;
                return;
            }
        }
    }

    void _set_special(int key, bool down) {
        switch(key) {
            case GLUT_KEY_LEFT:
                key_down[KEY_CURSOR_LEFT] = down;
                break;
            case GLUT_KEY_RIGHT:
                key_down[KEY_CURSOR_RIGHT] = down;
                break;
            case GLUT_KEY_UP:
                key_down[KEY_CURSOR_UP] = down;
                break;
            case GLUT_KEY_DOWN:
                key_down[KEY_CURSOR_DOWN] = down;
                break;
        }
    }

    void _keyboard_func(unsigned char c, int x, int y) {
        _set_key(c, true);
    }

    void _keyboard_up_func(unsigned char c, int x, int y) {
        _set_key(c, false);
    }

    void _special_func(int key, int x, int y) {
        _set_special(key, true);
    }
    
    void _special_up_func(int key, int x, int y) {
        _set_special(key, false);
        
    }

    void Tick() {
        for (int i = 0; i < KEY_LIMIT; ++i) {
            last_key_down[i] = this_key_down[i];
            this_key_down[i] = key_down[i];    }
    }

    void Init() {
        for (int i = 0; i < KEY_LIMIT; ++i) {
            this_key_down[i] = last_key_down[i] = key_down[i] = false;
        }
        glutIgnoreKeyRepeat(1);
        glutKeyboardFunc(_keyboard_func);
        glutKeyboardUpFunc(_keyboard_up_func);
        glutSpecialFunc(_special_func);
        glutSpecialUpFunc(_special_up_func);
    }

    bool IsKeyDown(int key) {
        if (key < 0 || key >= KEY_LIMIT) return false;
        return this_key_down[key];
    }
    bool WasKeyDown(int key) {
        if (key < 0 || key >= KEY_LIMIT) return false;
        return last_key_down[key];
    }

}  // keyboard